﻿using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using BPanel.Application.Nginx;
using BPanel.Application.Nginx.Model;
using BPanel.Core.Encrypt;
using BPanel.Core.Extensions;
using BPanel.Core.Extensions.Models;
using BPanel.Core.Middlewares;
using BPanel.Core.Repository;
using BPanel.Core.YidGenerator;
using BPanel.Database.Entities;
using BPanel.Database.Enums;
using BPanel.Web.ViewModels.Auth;
using BPanel.Web.ViewModels.System;
using BPanel.Web.ViewModels.WebSite;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;

namespace BPanel.Web.Controllers;

/// <summary>
/// API
/// </summary>
[Authorize]
[ApiController]
[Route("/api/")]
public class ApiController : ControllerBase
{
    private readonly IConfiguration _configuration;
    private readonly IFreeSql _freeSql;

    /// <summary>
    /// API
    /// </summary>
    public ApiController(IConfiguration configuration, IFreeSql freeSql)
    {
        _configuration = configuration;
        _freeSql = freeSql;
    }

    #region Auth

    /// <summary>
    /// 登录
    /// </summary>
    /// <param name="loginModel"></param>
    /// <returns></returns>
    [AllowAnonymous]
    [HttpPost("auth/login")]
    public async Task<ApiResponse<LoginViewModel>> Login([FromBody] LoginModel loginModel)
    {
        if (loginModel.Username.IsNullOrEmpty() || loginModel.Password.IsNullOrEmpty())
            throw new Exception("用户名或密码不能为空");

        var system = await _freeSql.Select<Database.Entities.System>().FirstAsync();

        if (system == null)
            throw new Exception("系统未初始化！");

        if (system.LockTime.AddMinutes(10) > DateTime.Now)
            throw new Exception("您的操作太频繁，请稍后重试");

        if (system.Username != loginModel.Username)
            throw new Exception("用户名或密码错误");

        if (system.Password != loginModel.Password.ToMd5String())
        {
            system.ErrorCount += 1;
            if (system.ErrorCount >= 5)
                system.LockTime = DateTime.Now;

            await _freeSql.Update<Database.Entities.System>().SetSource(system).ExecuteAffrowsAsync();

            throw new Exception("用户名或密码错误");
        }

        var tokenHandler = new JwtSecurityTokenHandler();
        var key = Encoding.ASCII.GetBytes(_configuration.GetValue<string>("JwtSecurityKey") ?? string.Empty); // 替换为你的密钥
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, system.Username) }),
            Expires = DateTime.UtcNow.AddDays(1),
            SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
        };
        
        // 登录错误信息归零
        system.ErrorCount = 0;
        system.LockTime = DateTime.MinValue;
        await _freeSql.Update<Database.Entities.System>().SetSource(system).ExecuteAffrowsAsync();
        
        var token = tokenHandler.CreateToken(tokenDescriptor);
        var tokenString = tokenHandler.WriteToken(token);
        
        return ApiResponse.Ok(new LoginViewModel()
        {
            Username = system.Username,
            Token = tokenString
        });
    }

    /// <summary>
    /// 修改密码
    /// </summary>
    /// <param name="param"></param>
    /// <returns></returns>
    [HttpPut("auth/update-password")]
    [Authorize]
    public async Task<ApiResponse> UpdatePasswordAsync([FromBody] UpdatePasswordModel param)
    {
        if (param.NewPassword != param.ReconfirmNewPassword)
            throw new Exception("两次密码输入不一致");

        var userClaim = HttpContext.User.Claims.Where(c => c.Type == ClaimTypes.Name).FirstOrDefault();
        if (userClaim == null)
            throw new Exception("登陆信息异常");

        var username = userClaim.Value;

        var system = await _freeSql.Select<Database.Entities.System>().Where(c => c.Username == username).FirstAsync();
        if (system == null)
            throw new Exception("用户不存在");

        if (system.Password != param.OldPassword.ToMd5String())
            throw new Exception("旧密码不正确");

        system.Password = param.NewPassword.ToMd5String();

        await _freeSql.Update<Database.Entities.System>().SetSource(system).ExecuteAffrowsAsync();

        return ApiResponse.Ok();
    }

    #endregion

    #region WebSite

    /// <summary>
    /// 站点列表
    /// </summary>
    /// <returns></returns>
    [HttpGet("web-site/list")]
    public async Task<ApiResponse<PagedList<WebSiteListModel>>> ListAsync()
    {
        var list = await _freeSql.Select<WebSite>().OrderByDescending(c => c.CreateTime)
            .ToListAsync(c => new WebSiteListModel()
            {
                Id = c.Id,
                Name = c.Name,
                RootDirectory = c.RootDirectory,
                Port = c.Port
            });
        var total = await _freeSql.Select<WebSite>().CountAsync();

        return ApiResponse.Ok(new PagedList<WebSiteListModel>(list.ToList(), Convert.ToInt32(total), 1, 10));
    }

    /// <summary>
    /// 新增站点
    /// </summary>
    /// <param name="param"></param>
    /// <returns></returns>
    [HttpPost("web-site/add")]
    public async Task<ApiResponse<bool>> AddAsync([FromBody] AddWebSiteModel param)
    {
        using var uow = _freeSql.CreateUnitOfWork();

        var model = new WebSite()
        {
            Id = Yid.NewId(),
            Name = param.Name,
            RootDirectory = $"/www/wwwroot/{param.Name}",
            Status = EnumStatus.Stop,
            Port = param.Port,
            PhpVersion = param.PhpVersion,
            Protocol = param.Protocol,
            SiteType = param.SiteType,
            CreateTime = DateTime.Now,
            ExpiredTime = param.ExpiredTime,
        };
        var domains = param.Domains.Select(c => new WebSiteDomain()
        {
            Id = Yid.NewId(),
            WebSiteId = model.Id,
            Domain = c,
        }).ToList();

        if (param.CreateDatabase)
        {
            var dbUsername = BuildHelper.GetRandomString(8);
            var dbPassword = BuildHelper.GetRandomString(8);
            // 创建数据库
            var database = new BPanel.Database.Entities.Database()
            {
                Id = Yid.NewId(),
                DatabaseType = EnumDatabaseType.Mysql,
                DatabaseName = param.Name,
                Username = dbUsername,
                Password = dbPassword,
            };
            await uow.Orm.Insert(database).ExecuteAffrowsAsync();
        }

        // 在事务内尽量不使用FreeSql，以免不处在一个事务
        await uow.Orm.Insert(model).ExecuteAffrowsAsync();
        await uow.Orm.Insert(domains).ExecuteAffrowsAsync();

        // 创建站点的nginx配置文件
        ConfOperation.CreateWebSite(new CreateNginxModel
        {
            Name = param.Name,
            Port = param.Port,
            Domains = param.Domains,
            SiteType = param.SiteType,
            PhpVersion = param.PhpVersion
        });

        // nginx -s reload 重新加载配置
        ConfOperation.NginxReload();

        // 新增数据库
        if (param.CreateDatabase)
        {
        }

        uow.Commit();

        return ApiResponse.Ok(true);
    }

    /// <summary>
    /// 删除站点
    /// </summary>
    /// <returns></returns>
    [HttpPut("web-site/delete")]
    public async Task<ApiResponse<bool>> DeleteAsync([FromBody] DeleteWebSiteModel param)
    {
        var webSite = await _freeSql.Select<WebSite>().Where(c => c.Id == param.Id).FirstAsync();

        // 删除nginx配置
        ConfOperation.DeleteNginxConf(webSite.Name);
        // 删除站点目录
        ConfOperation.DeleteWebsiteWwwRoot(webSite.Name);

        // 删除数据库
        if (param.DeleteDatabase)
        {
        }

        await _freeSql.Delete<WebSite>(webSite).ExecuteAffrowsAsync();
        await _freeSql.Delete<WebSiteDomain>(new WebSiteDomain() { WebSiteId = webSite.Id }).ExecuteAffrowsAsync();

        ConfOperation.NginxReload();

        return ApiResponse.Ok(true);
    }

    #endregion

    #region System

    /// <summary>
    /// 检测是否初始化系统
    /// </summary>
    /// <returns></returns>
    [HttpGet("system/check-init")]
    public async Task<ApiResponse<bool>> IsInitAsync()
    {
        var system = await _freeSql.Select<Database.Entities.System>().FirstAsync();
        if (system == null)
            return ApiResponse.Ok(false);

        return ApiResponse.Ok(true);
    }

    /// <summary>
    /// 初始化系统
    /// </summary>
    /// <returns></returns>
    [HttpPost("system/init")]
    public async Task<ApiResponse<bool>> InitAsync([FromBody] InitModel model)
    {
        var system = await _freeSql.Select<Database.Entities.System>().AnyAsync();
        if (system)
            throw new Exception("系统已初始化，不能再次初始化");

        await _freeSql.Insert(new BPanel.Database.Entities.System()
        {
            Id = Yid.NewId(),
            Title = "bPanel服务器管理面板",
            DefaultSiteDirectory = "/www/wwwroot",
            Version = "V0.0.1",
            Port = 8888,
            Username = model.Username,
            Password = model.Password.ToMd5String(),
            LockTime = DateTime.MinValue,
        }).ExecuteAffrowsAsync();

        return ApiResponse.Ok(true);
    }

    /// <summary>
    /// 获取设置
    /// </summary>
    /// <returns></returns>
    [HttpGet("system/setting")]
    public async Task<ApiResponse<SystemSettingModel>> SettingAsync()
    {
        var system = await _freeSql.Select<Database.Entities.System>().FirstAsync();

        var res = new SystemSettingModel()
        {
            Title = system.Title,
            DefaultSiteDirectory = system.DefaultSiteDirectory,
            Port = system.Port
        };

        return ApiResponse.Ok(res);
    }

    /// <summary>
    /// 修改设置
    /// </summary>
    /// <param name="param"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    [HttpPost("system/setting")]
    public async Task<ApiResponse<bool>> SettingAsync([FromBody] SystemSettingModel param)
    {
        var system = await _freeSql.Select<Database.Entities.System>().FirstAsync();

        if (system == null)
            throw new Exception("系统异常");

        system.Title = param.Title;
        system.DefaultSiteDirectory = param.DefaultSiteDirectory;
        system.Port = param.Port;

        var res = await _freeSql.Update<Database.Entities.System>().SetSource(system).ExecuteAffrowsAsync();

        return ApiResponse.Ok(res > 0);
    }

    #endregion

    #region Store

    /// <summary>
    /// 获取PHP版本列表
    /// </summary>
    /// <returns></returns>
    [HttpGet("store/php-version-list")]
    public ApiResponse<List<KeyValueModel>> PhpVersionListAsync()
    {
        var dic = typeof(EnumPhpVersion).ToDescriptionList();

        return ApiResponse.Ok(dic);
    }

    /// <summary>
    /// 安装PHP指定版本
    /// </summary>
    /// <returns></returns>
    [HttpPost("store/install-php-version")]
    public Task<ApiResponse> InstallPhpVersionAsync()
    {
        return Task.FromResult(ApiResponse.Ok());
    }

    /// <summary>
    /// 移除PHP指定版本
    /// </summary>
    /// <returns></returns>
    [HttpPut("store/remove-php-version")]
    public Task<ApiResponse> RemovePhpVersionAsync()
    {
        return Task.FromResult(ApiResponse.Ok());
    }

    #endregion
}